home *** CD-ROM | disk | FTP | other *** search
/ Graphics Plus / Graphics Plus.iso / general / modelers / geomview / source.lha / Geomview / src / bin / stereo / stereo.c < prev    next >
C/C++ Source or Header  |  1993-11-09  |  15KB  |  602 lines

  1. #include <stdio.h>
  2. #include <forms.h>
  3. #include <gl/gl.h>
  4. #include <gl/device.h>
  5. #include <gl/get.h>
  6.  
  7. #include <ooglutil.h>
  8. #include <streampool.h>
  9. #include <camera.h>
  10. #include <window.h>
  11. #include <lisp.h>
  12.  
  13. #include <sys/signal.h>
  14.  
  15. #include "sterui.h"
  16.  
  17. extern HandleOps CamOps, WindowOps;
  18. static void monitor(int mode);
  19.  
  20. #define    CURRENT        0
  21. #define    ST_MONO        1
  22. #define    ST_CROSSEYED    2
  23. #define    ST_HARDWARE    3
  24. #define    ST_COLORED    4
  25.  
  26. #define    FOR_SOMETHING    0
  27. #define    FOR_FOCUS    1
  28. #define    FOR_REDRAW    2
  29.  
  30.  
  31. Camera *cam;
  32. WnWindow *win;
  33. int camwinseq;
  34. int expectredraw;
  35. Pool *io;
  36. Lake *lake;
  37. long mainwin = -1, helpwin = -1, morewin = -1;    /* GL window id's */
  38.  
  39.             /* Values cached from current camera & window */
  40. int    isstereo = 0;
  41. float    pixelaspect = 1;    /* pixel aspect */
  42. float    camaspect = 1.3;    /* Camera aspect ratio, xsize/ysize */
  43. float    halffield = .4;        /* half linear field (= tan(fov/2)) */
  44. float    halfyfield = .4;    /* half Y-axis linear field */
  45. float    focallen = 3;        /* focal length */
  46. char    *camname = "focus";    /* Use this camera */
  47. int    smode = ST_MONO;    /* Last known mode */
  48. WnPosition curpos;
  49. int    xsize, ysize;
  50.  
  51.     /* Stereo convergence angle to an object in the nominal plane of view */
  52. float    halfconv = .1;        /* tan(current convergence angle/2) */
  53. float    halfmaxconv = .22;    /* tan(max allowable convergence/2) */
  54. int    swapeyes = 1;
  55.  
  56.     /* Hardware parameters */
  57. float    pixperinch;
  58. int    xscreen, yscreen;
  59. float    screenwidth;
  60.  
  61.     /* Warmware parameter? */
  62. float    ocularsep = 1.15;    /* 2*ocularsep inches between human eyes */
  63.  
  64. current_mode()
  65. {
  66.     if(cam == NULL || win == NULL) {
  67.     fprintf(stderr, "Hey? -- stereo sleeping...\n");
  68.     unqdevice(WINSHUT);
  69.     unqdevice(WINQUIT);
  70.     pause();
  71.     return ST_MONO;
  72.     }
  73.     CamGet(cam, CAM_STEREO, &isstereo);
  74.     CamGet(cam, CAM_HALFYFIELD, &halfyfield);
  75.     CamGet(cam, CAM_HALFFIELD, &halffield);
  76.     CamGet(cam, CAM_FOCUS, &focallen);
  77.     CamGet(cam, CAM_ASPECT, &camaspect);
  78.     WnGet(win, WN_PIXELASPECT, &pixelaspect);
  79.     WnGet(win, WN_CURPOS, &curpos);
  80.     xsize = curpos.xmax - curpos.xmin + 1;
  81.     ysize = curpos.ymax - curpos.ymin + 1;
  82.     return smode;
  83. }
  84.  
  85. void
  86. set_mode(int mode, int why)
  87. {
  88.     char *layout = "no";
  89.     int stereo = 1;
  90.     int gap = 0;
  91.     int dx, hvpwidth;
  92.     float halfxfield, newxfield, newyfield, newfocallen, newaspect, focalscale;
  93.     int got;
  94.     char winstuff[80];
  95.     char camstuff[80];
  96.     char advice[120];
  97.     static int oldxsize = -1, oldysize;
  98.  
  99.     request_camwin();
  100.     got = camwinseq;
  101.     do {
  102.     LFree( LEvalSexpr(lake) );
  103.     } while(got == camwinseq);    /* Keep reading until we see a camera/window. */
  104.     got = current_mode();
  105.     if(mode == 0)
  106.     mode = got;
  107.  
  108.     if(why == FOR_REDRAW && oldxsize == xsize && oldysize == ysize) {
  109.     expectredraw = 0;
  110.     return;
  111.     }
  112.  
  113. #ifdef notdef
  114. fprintf(stderr, "# halfyfield %.3f  halffield %.3f fov %.3f\r\n",
  115.     halfyfield, halffield, 2*DEGREES(atan(halffield)));
  116. #endif
  117.  
  118.     winstuff[0] = '\0';
  119.     camstuff[0] = '\0';
  120.     hvpwidth = xsize/2;
  121.     newyfield = halfyfield;
  122.     focalscale = 1;
  123.  
  124.     printf("(progn\n");
  125.  
  126.     switch(mode) {
  127.     case ST_MONO:
  128.     monitor(HZ60);
  129.     pixelaspect = 1;
  130.     layout = "no";
  131.     stereo = 0;
  132.     camaspect = (double)xsize / ysize;
  133.     newxfield = camaspect>1 ? camaspect*halffield : halffield;
  134.     break;
  135.  
  136.     case ST_CROSSEYED:
  137.     monitor(HZ60);
  138.     hvpwidth = xsize/4;
  139.     dx = xsize/2;
  140.     pixelaspect = 1;
  141.     layout = "horizontal";
  142.     camaspect = .5*xsize / ysize;
  143.  
  144.     /* Field-of-view is related to convergence angle in crosseyed view:
  145.      *  tan(xfov/2) = tan(conv/2) / (1 + ocularsep/(viewportwidth/2)).
  146.      * Push the camera back so as to frame the same object, assuming its
  147.      * "focus" distance correctly reflects the object of interest.
  148.      */
  149.  
  150.     halfxfield = camaspect>1 ? halffield*camaspect : halffield;
  151.     newxfield = halfconv / (1 + ocularsep*pixperinch / hvpwidth);
  152.     focalscale = halfxfield / newxfield;
  153.     break;
  154.  
  155.     case ST_HARDWARE:
  156.     monitor(STR_RECT);
  157.     gap = 40;
  158.     dx = 0;
  159.     pixelaspect = .5;
  160.     layout = "vertical";
  161.     sprintf(winstuff, "position %d %d %d %d\n",
  162.         curpos.xmin, curpos.xmax, 0, yscreen-1);
  163.  
  164.     camaspect = (double)xsize / ((yscreen - gap) / 2);
  165.     halfxfield = camaspect>1 ? halffield*camaspect : halffield;
  166.     newxfield = halfconv / (pixelaspect * ocularsep*pixperinch / hvpwidth);
  167.     focalscale = halfxfield / newxfield;
  168.     break;
  169.  
  170.     case ST_COLORED:
  171.     monitor(HZ60);
  172.     gap = 0;
  173.     dx = 0;
  174.     pixelaspect = 1;
  175.     layout = "colored";
  176.     camaspect = (double)xsize / ysize;
  177.     halfxfield = halfyfield*camaspect;
  178.     newxfield = halfconv / (ocularsep*pixperinch / hvpwidth);
  179.     focalscale = halfxfield / newxfield;
  180.     break;
  181.  
  182.     default:
  183.     fprintf(stderr, "set_mode(%d)?\n", mode);
  184.     }
  185.  
  186.     halfyfield = newxfield/camaspect;
  187.     halffield = newxfield < halfyfield ? newxfield : halfyfield;
  188.     newfocallen = focallen * focalscale;
  189. #ifdef notdef
  190. fprintf(stderr, "# NEW halfxfield %.3f halfyfield %.3f  aspect %.3f focus %.2f  fov %.3f  hconv %.1f\r\n",
  191.         halfxfield, halfyfield, camaspect, newfocallen,
  192.         2*DEGREES(atan(halffield)), 2*DEGREES(atan(halfconv)));
  193. #endif
  194.  
  195.     if(fabs(focalscale - 1) > .02 && why == FOR_SOMETHING && !fl_get_button(FixedCamButton)) {
  196.     float near, far;
  197.     CamGet(cam, CAM_NEAR, &near);
  198.     CamGet(cam, CAM_FAR, &far);
  199.     printf("(transform %s self self translate 0 0 %g)\n",
  200.         camname, focallen - newfocallen);
  201.     sprintf(camstuff, "focus %g near %g far %g\n",
  202.         newfocallen, near*focalscale, far*focalscale);
  203.     focallen = newfocallen;
  204.     }
  205.  
  206.     printf("(stereowin %s %s %d)\n", camname, layout, gap);
  207.     printf("(merge window %s { pixelaspect %g %s })\n",
  208.     camname, pixelaspect, winstuff);
  209.     printf("(merge camera %s {\n\
  210.     %s perspective 1 frameaspect %g halfyfield %g\n\
  211.     stereyes\n\
  212.     transform { 1 0 0 0  0 1 0 0  %g 0 1 0  %g 0 0 1 }\n\
  213.     transform { 1 0 0 0  0 1 0 0  %g 0 1 0  %g 0 0 1 }\n\
  214. }))",
  215.     camname, camstuff, camaspect, halfyfield,
  216.     -swapeyes*halfconv, -swapeyes*halfconv*focallen,
  217.     swapeyes*halfconv, swapeyes*halfconv*focallen);
  218.     fflush(stdout);
  219.  
  220.     /* Advise viewing from distance such that the field-of-view is correct. */
  221.     halfxfield = halffield * (camaspect>1 ? camaspect : 1);
  222.     sprintf(advice, "%.1f degree field of view\nBest view ~%.0f\" from screen",
  223.     2*DEGREES(atan(halffield)), hvpwidth/pixperinch / halfxfield);
  224.  
  225.     fl_set_object_label(BestViewText, advice);
  226.  
  227.     isstereo = stereo;
  228.     expectredraw = 1;
  229.     oldxsize = xsize;
  230.     oldysize = ysize;
  231.  
  232.     if(stereo)
  233.     fl_show_object(SwapButton);
  234.     else
  235.     fl_hide_object(SwapButton);
  236.     if(fl_get_browser(StereoBrowser) != mode)
  237.     fl_select_browser_line(StereoBrowser, mode);
  238. }
  239.  
  240. void
  241. ConvProc(FL_OBJECT *obj, long arg)
  242. {
  243.     float v = fl_get_slider_value(obj);
  244.  
  245.     halfconv = tan(RADIANS(v/2));
  246.     if(isstereo)
  247.     set_mode(CURRENT, FOR_SOMETHING);
  248. }
  249.  
  250. void
  251. StereoProc(FL_OBJECT *obj, long arg)
  252. {
  253.     set_mode(fl_get_browser(obj), FOR_SOMETHING);
  254. }
  255.  
  256. void
  257. SwapProc(FL_OBJECT *obj, long arg)
  258. {
  259.     swapeyes = fl_get_button(obj) ? -1 : 1;
  260.     set_mode(CURRENT, FOR_SOMETHING);
  261. }
  262.  
  263.  
  264. LDEFINE(stereowin, LVOID, "")
  265. {
  266.     char *cam = NULL, *mode = NULL;
  267.     LDECLARE(("stereowin", LBEGIN,
  268.     LSTRING, &cam,
  269.     LSTRING, &mode,
  270.     LREST, NULL,
  271.     LEND));
  272.     if(mode == NULL)
  273.     return Lnil;
  274.     switch(mode[0]) {
  275.     case 'n': smode = ST_MONO; break;        /* "no" */
  276.     case 'h': smode = ST_CROSSEYED; break;    /* "horizontal" */
  277.     case 'v': smode = ST_HARDWARE; break;    /* "vertical" */
  278.     case 'c': smode = ST_COLORED; break;    /* "colored" */
  279.     default:
  280.     fprintf(stderr,
  281.       "stereo: Can't understand  '(stereowin %s %s)' from geomview.\n",
  282.         cam, mode);
  283.     }
  284.     return Lt;
  285. }
  286.  
  287.  
  288. LDEFINE(redraw, LVOID, "")
  289. {
  290.     LDECLARE(("redraw", LBEGIN,
  291.     LREST, NULL,
  292.     LEND));
  293.  
  294.     if(expectredraw-- <= 0) {
  295.     expectredraw = 1;        /* Prevent reentrant calls */
  296.     set_mode(CURRENT, FOR_REDRAW);
  297.     }
  298.     return Lt;
  299. }
  300.  
  301.  
  302. static char simplepick[] = "(pick %s nil * nil nil nil nil nil nil nil)";
  303.  
  304. LDEFINE(pick, LVOID, "")
  305. {
  306.     float z;
  307.     HPoint3 pt;
  308.     char *me, *it;
  309.     int npt = 4;
  310.     static int picking = 0;
  311.  
  312.     LDECLARE(("pick", LBEGIN,
  313.     LSTRING, &me,
  314.     LSTRING, &it,
  315.     LHOLD, LARRAY, LFLOAT, &pt, &npt,
  316.     LREST, NULL,
  317.     LEND));
  318.  
  319.     fl_set_object_boxtype(FocalButton, FL_UP_BOX);
  320.     if(picking) return Lnil;
  321.     picking = 1;
  322.  
  323.     printf("(progn (uninterest\n");
  324.     printf(simplepick, camname);
  325.     printf(")");
  326.     if(npt == 4) {
  327.     printf("(merge camera %s { focus %g }))\n", camname, -pt.z / pt.w);
  328.     fflush(stdout);
  329.     set_mode(CURRENT, FOR_FOCUS);
  330.     } else {
  331.     printf(")\n");    /* Close the progn */
  332.     fflush(stdout);
  333.     }
  334.     picking = 0;
  335.     return Lt;
  336. }
  337.  
  338. static char simplemerge[] = "(merge camera %s *)";
  339.  
  340. LDEFINE(merge, LVOID,
  341.        "(merge camera CAM-ID  { CAMERA ... } )")
  342. {
  343.   char *opsname = NULL;
  344.   int c, id;
  345.   LObject *kw = NULL, *idarg = NULL;
  346.   float newfocallen = focallen;
  347.  
  348.   if (lake == NULL)
  349.     return Lt;
  350.  
  351.   /* All the work of this function is done at parse time. */
  352.  
  353.   /* parse first arg [ops]: */
  354.   if (! LakeMore(lake,c) || (kw = LSexpr(lake)) == Lnil ||
  355.       !LFROMOBJ(LSTRING)(kw, &opsname) || strcmp(opsname, "camera") != 0) {
  356.     OOGLSyntax(stdin, "merge: expected \"camera\", got \"%s\"", opsname);
  357.     goto parsefail;
  358.   }
  359.  
  360.   /* parse 2nd arg; it's a string (id) */
  361.   if (! LakeMore(lake,c) || (idarg = LEvalSexpr(lake)) == Lnil) {
  362.     OOGLSyntax(stdin,"\"merge\": expected CAM-ID");
  363.     goto parsefail;
  364.   }
  365.  
  366.  
  367.   cam = NULL;
  368.   if(CamOps.strmin(POOL(lake), NULL, &cam) == 0) {
  369.     OOGLSyntax(stdin, "\"merge\": error reading camera");
  370.     goto parsefail;
  371.   }
  372.  
  373.   CamGet(cam, CAM_FOCUS, &focallen);
  374.   if(fabs(focallen - newfocallen) > .01) {
  375.     focallen = newfocallen;
  376.     if(!expectredraw)
  377.     set_mode(CURRENT, FOR_FOCUS);
  378.   }
  379.  parsefail:
  380.   LFree(kw);
  381.   LFree(idarg);
  382.   return Lt;
  383. }
  384.  
  385. request_camwin()
  386. {
  387.     printf("\
  388. (progn (echo (stereowin %s)) (echo \"(camwin \") (write camera - %s) (write window - %s) (echo \"\\n)\\n\") )\n",
  389.     camname, camname, camname);
  390.     fflush(stdout);
  391. }
  392.  
  393. LDEFINE(camwin, LVOID, "")
  394. {
  395.     if(lake == NULL) return Lt;
  396.     camwinseq++;
  397.     if(CamStreamIn(POOL(lake), NULL, &cam) <= 0) {
  398.     OOGLSyntax(stdin, "stereo: couldn't read camera");
  399.     return Lnil;
  400.     }
  401.     if(WnStreamIn(POOL(lake), NULL, &win) <= 0) {
  402.     OOGLSyntax(stdin, "stereo: couldn't read window");
  403.     return Lnil;
  404.     }
  405.     return Lt;
  406. }
  407.  
  408. void
  409. FocalProc(FL_OBJECT *obj, long arg)
  410. {
  411.     printf("(interest ");
  412.     printf(simplepick, camname);
  413.     printf(")\n");
  414.     fflush(stdout);
  415.     fl_set_object_label(BestViewText, "Click right mouse on point");
  416.     fl_set_object_boxtype(obj, FL_DOWN_BOX);
  417. }
  418.  
  419. static char *HelpText[] = {
  420. #include "help.c"
  421. };
  422.  
  423. void HelpProc(FL_OBJECT *obj, long arg)
  424. { helpwin = fl_show_form(Help, FL_PLACE_SIZE, TRUE, "Stereo Help"); }
  425.  
  426. int
  427. validinput(FL_OBJECT *obj, float *val)
  428. {
  429.   char *s = fl_get_input(obj);
  430.   char *s0 = s;
  431.   float v;
  432.   v = strtod(s, &s);
  433.   if(s == s0) return 0;
  434.   if(*val == v) return -1;
  435.   *val = v;
  436.   return 1;
  437. }
  438.  
  439. void updateMore()
  440. {
  441.   char s[80];
  442.   fl_freeze_form(More);
  443.   sprintf(s, "%.2f", screenwidth);
  444.   fl_set_input(ScreenWidthInput, s);
  445.   sprintf(s, "%.2f", 2*ocularsep);
  446.   fl_set_input(OcularInput, s);
  447.   fl_unfreeze_form(More);
  448. }
  449.  
  450. void
  451. OcularSepProc(FL_OBJECT *obj, long arg)
  452. {
  453.   if(validinput(obj, &ocularsep) > 0) {
  454.     ocularsep *= .5;
  455.     set_mode(CURRENT, FOR_SOMETHING);
  456.   }
  457.   updateMore();
  458. }
  459.  
  460. void
  461. ScreenWidthProc(FL_OBJECT *obj, long arg)
  462. {
  463.   if(validinput(obj, &screenwidth) > 0 && screenwidth > 0) {
  464.     pixperinch = xscreen / screenwidth;
  465.     set_mode(CURRENT, FOR_SOMETHING);
  466.   }
  467.   updateMore();
  468. }
  469.  
  470. void
  471. CamNameProc(FL_OBJECT *obj, long arg)
  472. {
  473.   char *is = fl_get_input(CamNameInput);
  474.   if(strcmp(camname, is) && is[0] != '\0') {
  475.     camname = is;
  476.     request_camwin();
  477.   }
  478. }
  479.  
  480. void MoreProc(FL_OBJECT *obj, long arg)
  481. {
  482.   updateMore();
  483.   morewin = fl_show_form(More, FL_PLACE_SIZE, TRUE, "Stereo Parameters");
  484. }
  485.  
  486. static void
  487. monitor(int mode)
  488. {
  489.     if((mode == STR_RECT) != (getmonitor() == STR_RECT) && !getenv("NOMON"))
  490.     setmonitor(mode);
  491. }
  492.  
  493. void
  494. die(int sig)
  495. {
  496.     monitor(HZ60);
  497.     exit(0);
  498. }
  499.  
  500. void
  501. QuitProc(FL_OBJECT *obj, long arg)
  502. {
  503.     die(0);
  504. }
  505.  
  506. void
  507. DoneProc(FL_OBJECT *obj, long arg)
  508. {
  509.    fl_hide_form(obj->form);
  510. }
  511.  
  512. main(int argc, char *argv[])
  513. {
  514.     int i, c;
  515.  
  516.     io = PoolStreamOpen("stdio", stdin, 0, &CamOps);
  517.     PoolStreamOpen("stdio", stdout, 1, &CamOps);
  518.     lake = LakeDefine(stdin, stdout, io);
  519.  
  520.     LInit();
  521.     LDefun("pick", Lpick, Hpick);
  522.     LDefun("redraw", Lredraw, Hredraw);
  523.     LDefun("merge", Lmerge, Hmerge);
  524.     LDefun("camwin", Lcamwin, Hcamwin);
  525.     LDefun("stereowin", Lstereowin, Hstereowin);
  526.  
  527.     foreground();
  528.     fl_init();
  529.     create_the_forms();
  530.  
  531.  
  532.     signal(SIGHUP, die);
  533.     signal(SIGINT, die);
  534.  
  535.     /* This order must match that of the ST_* define's */
  536.     fl_add_browser_line(StereoBrowser, "Monoscopic");
  537.     fl_add_browser_line(StereoBrowser, "Crosseyed");
  538.     fl_add_browser_line(StereoBrowser, "Hardware");
  539.     fl_add_browser_line(StereoBrowser, "Red/Cyan");
  540.  
  541.     fl_set_slider_bounds(ConvSlider, 1.5, DEGREES(atan(halfmaxconv)));
  542.     fl_set_slider_value(ConvSlider, 2*DEGREES(atan(halfconv)));
  543.     mainwin = fl_show_form(stereo, FL_PLACE_SIZE, TRUE, "Stereo View");
  544.     fl_qdevice(WINSHUT);
  545.     fl_qdevice(WINQUIT);
  546.  
  547.     fl_set_input(CamNameInput, camname);
  548.  
  549.     for(i = 0; i < COUNT(HelpText); i++)
  550.     fl_add_browser_line(HelpBrowser, HelpText[i]);
  551.  
  552.     /* Screen pixel density */
  553.     xscreen = getgdesc(GD_XPMAX);
  554.     yscreen = getgdesc(GD_YPMAX);
  555.     screenwidth = getgdesc(GD_XMMAX) * .03937;
  556.     pixperinch = xscreen / screenwidth;
  557.  
  558.     printf("(interest (redraw))\n");
  559.     printf("(interest (merge camera))\n");
  560.     request_camwin();
  561.     for(i = 1; i < argc; i++) {
  562.     if(!strcmp(argv[i], "-fixed")) {
  563.         fl_set_button(FixedCamButton, 1);
  564.     } else if(!strcmp(argv[i], "-unfixed")) {
  565.         fl_set_button(FixedCamButton, 0);
  566.     } else if(!strncmp(argv[i], "-cam", 4)) {    /* -cam or -camera */
  567.         fl_set_input(CamNameInput, argv[++i]);
  568.         CamNameProc(CamNameInput, 0);
  569.     } else if(!strcmp(argv[i], "-mode")) {
  570.         /* ... */
  571.     }
  572.     }
  573.  
  574.     for(;;) {
  575.     if((c = async_fnextc(stdin, 0)) == NODATA) {
  576.         static struct timeval tenth = { 0, 100000 }; /* 0.1 sec */
  577.         select(0, NULL, NULL, NULL, &tenth);
  578.     } else {
  579.         /* Got a Lisp expression */
  580.         c = camwinseq;
  581.         LFree(LEvalSexpr(lake));
  582.         /* If it was a camera/window pair, ... */
  583.         if(c != camwinseq)
  584.         set_mode(current_mode(), FOR_REDRAW);
  585.     }
  586.     fl_check_forms();
  587.     if(fl_qtest()) {
  588.         short v;
  589.  
  590.         switch( fl_qread(&v) ) {
  591.         case WINQUIT:
  592.         die(0);
  593.  
  594.         case WINSHUT:
  595.         if(v == mainwin) die(0);
  596.         else if(v == helpwin) fl_hide_form(Help), helpwin = -1;
  597.         else if(v == morewin) fl_hide_form(More), morewin = -1;
  598.         }
  599.     }
  600.     }
  601. }
  602.